feat: adds long lived refresh token feature for ci#475
Open
Conversation
6b414ed to
da30ac7
Compare
src/api/apollo.client.ts
Outdated
| } | ||
| } | ||
|
|
||
| let response = await fetch(input, { ...init, headers }); |
Member
There was a problem hiding this comment.
If you dont need the body consider performing a HEAD request. This improves the memory footprint
https://undici.nodejs.org/#/?id=garbage-collection
Contributor
Author
There was a problem hiding this comment.
We need the body for the graphql queries and mutations, as we need Apollo to parse the GraphQL data and the request.
2fa5f27 to
f434a52
Compare
f434a52 to
ca5cdb6
Compare
ca5cdb6 to
1448d20
Compare
1448d20 to
109514a
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
CI Login Token Exchange: Long-Lived Refresh Tokens for Headless Auth
Summary
Adds support for long-lived organization-scoped refresh tokens for headless CI/CD pipelines. Users can provision a token once (interactive) and use it in CI without running
hd auth loginin the pipeline.Updates (Provision orgId from User Setup): Provision no longer requires
--org-id; orgId is obtained from the user setup API. Thehd auth-ci logincommand has been removed—scans exchange the CI token for an access token automatically viarequireAccessTokenForScan.Design
Flow
sequenceDiagram participant User participant Login participant Provision participant UserSetup participant Scan User->>Login: hd auth login Login->>Login: OAuth PKCE, persist tokens (keyring) User->>Provision: hd auth-ci provision Provision->>UserSetup: getUserSetupStatus / completeUserSetup UserSetup-->>Provision: orgId Provision->>IAM: getOrgAccessTokens(orgId, null) [Bearer from login] IAM-->>Provision: refreshToken (long-lived) Provision->>Provision: saveCIToken, saveCIOrgId Note over User: CI pipeline runs (headless) User->>Scan: hd scan eol (HD_AUTH_TOKEN, HD_ORG_ID set) Scan->>Scan: requireAccessTokenForScan → requireCIAccessToken Scan->>IAM: getOrgAccessTokens(orgId, refreshToken) IAM-->>Scan: accessToken, refreshToken (maybe rotated) Scan->>Scan: uses accessToken for API callsAuth Resolution Order
requireAccessTokenForScan(used by scan, Apollo default,completeUserSetup) now:getCIToken()orconfig.accessTokenFromEnv→ use CI path (requireCIAccessToken)CI tokens come from:
HD_AUTH_TOKEN,HD_ORG_ID,HD_ACCESS_TOKEN~/.hdcli/ci-token(encrypted, machine-bound)Prerequisites
UserSetupStatusschema ({ isComplete, orgId }) is required.Changes
Commands
hd auth-ci provisionhd auth loginfirst). Obtains orgId from user setup API. Saves to~/.hdcli/ci-tokenand outputs token for CI secrets.Removed:
hd auth-ci login— redundant. Scans callrequireAccessTokenForScan→requireCIAccessToken, which exchanges the CI token internally.New / Updated Files
src/commands/auth-ci/provision.ts– CI provision (no--org-id; usesensureUserSetupfor orgId)src/api/user-setup.client.ts–getUserSetupStatusandcompleteUserSetupreturn{ isComplete, orgId };ensureUserSetupreturns orgIdsrc/api/gql-operations.ts–userSetupStatusQueryandcompleteUserSetupMutationuseUserSetupStatusobject schemasrc/service/ci-auth.svc.ts– CI auth path; error messages updated (no--org-idreferences)src/service/ci-token.svc.ts– CI token storage (env + encrypted file viaconf);saveCIOrgId/getCIOrgIdfor org persistencesrc/api/ci-token.client.ts– IAMgetOrgAccessTokensclient (provisionCIToken,exchangeCITokenForAccess)src/api/apollo.client.ts– Extracted fromnes.client.ts; shared Apollo factory with token providersrc/config/constants.ts– AddedENABLE_AUTH,ENABLE_USER_SETUP,ciTokenFromEnv,orgIdFromEnv,accessTokenFromEnv, IAM configsrc/service/auth.svc.ts–requireAccessTokenForScandelegates to CI path first, re-exportsCITokenErrorREADME
hd auth login→hd auth-ci provision(no--org-id)hd scan eoldirectly withHD_AUTH_TOKENandHD_ORG_ID(no eval step)Other
nes.client.ts: Uses sharedcreateApollofromapollo.client.tsuser-setup.client.ts:completeUserSetupusesrequireAccessTokenForScan;ensureUserSetupextended to return orgId for provisionUsage
One-time setup (interactive):
Copy token output into CI secrets:
HD_AUTH_TOKEN,HD_ORG_ID(orgId also stored at provision time when using local file).CI pipeline:
Gaps & Follow-ups
ghcr.io/herodevs/eol-scansupportsHD_AUTH_TOKEN/HD_ORG_ID.ENABLE_AUTHis false or with CI token injection.